﻿using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;

namespace TCPActivePull.Service;

/// <summary>
/// Modbus单设备模拟器（仅用IP访问，固定端口5020和UnitId=1）
/// </summary>
public class ModbusDeviceSimulatorBackgroundService : BackgroundService
{
    private readonly ModbusDeviceSimulator _simulator;
    private readonly ILogger<ModbusDeviceSimulatorBackgroundService> _logger;
    // 【固定】模拟器IP和端口（无需配置）
    private const string DefaultSimulatorIp = "127.0.0.1";
    private const int DefaultSimulatorPort = 502;

    public ModbusDeviceSimulatorBackgroundService(ILogger<ModbusDeviceSimulatorBackgroundService> logger)
    {
        _logger = logger;
        // 初始化模拟器（固定IP和端口）
        _simulator = new ModbusDeviceSimulator(DefaultSimulatorIp, DefaultSimulatorPort);
        // 初始化单设备（固定UnitId=1）
        InitializeDeviceRegisters(_simulator);
    }

    // 【修改】初始化单设备（固定UnitId=1，仅需IP标识）
    private void InitializeDeviceRegisters(ModbusDeviceSimulator simulator)
    {
        // 设备寄存器配置（与服务端寄存器地址对应）
        var deviceRegisters = new Dictionary<ushort, ushort>
        {
            { 0x0000, 225 },   // 寄存器0：22.5℃（环境温度，Scale=0.1）
            { 0x0001, 650 },   // 寄存器1：65.0%（环境湿度，Scale=0.1）
            { 0x0002, 1013 },  // 寄存器2：101.3kPa（大气压力，Scale=0.01）
            { 0x0003, 500 }    // 寄存器3：5.0m/s（风速，Scale=0.01）
        };

        // 固定UnitId=1，无需配置
        simulator.InitializeSingleDevice(
            deviceName: "环境监测设备",
            registers: deviceRegisters);

        _logger.LogInformation("模拟器单设备初始化完成：UnitId=1（固定），寄存器数量={RegisterCount}", deviceRegisters.Count);
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation(
            "Modbus单设备模拟器启动中... 监听地址：{Ip}:{Port}",
            DefaultSimulatorIp,
            DefaultSimulatorPort);

        try
        {
            await _simulator.StartAsync(stoppingToken);
        }
        catch (Exception ex)
        {
            _logger.LogCritical(ex, "Modbus单设备模拟器运行异常，已停止（端口：{Port}）", DefaultSimulatorPort);
            throw;
        }
    }

    public override async Task StopAsync(CancellationToken cancellationToken)
    {
        _simulator.Stop();
        _logger.LogInformation("Modbus单设备模拟器已停止（{Ip}:{Port}）", DefaultSimulatorIp, DefaultSimulatorPort);
        await base.StopAsync(cancellationToken);
    }
}

/// <summary>
/// 模拟器核心（固定UnitId=1，仅用IP访问）
/// </summary>
internal class ModbusDeviceSimulator
{
    private readonly TcpListener _server;
    private bool _isRunning = false;
    private ModbusDevice? _singleDevice; // 固定单设备（UnitId=1）
    private const byte FixedUnitId = 1; // 固定设备地址

    public ModbusDeviceSimulator(string ip, int port)
    {
        var listenIp = IPAddress.Parse(ip);
        _server = new TcpListener(listenIp, port);
    }

    // 【修改】初始化单设备（移除UnitId参数，固定为1）
    public void InitializeSingleDevice(string deviceName, Dictionary<ushort, ushort> registers)
    {
        if (_singleDevice != null)
        {
            throw new InvalidOperationException("模拟器仅支持1个设备，已初始化过");
        }
        _singleDevice = new ModbusDevice(FixedUnitId, deviceName, registers);
        Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 模拟器设备配置：名称={deviceName}，UnitId=1（固定），寄存器数={registers.Count}");
    }

    public async Task StartAsync(CancellationToken stoppingToken)
    {
        if (_isRunning)
        {
            Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 模拟器已运行（{_server.LocalEndpoint}）");
            return;
        }
        if (_singleDevice == null)
        {
            throw new InvalidOperationException("请先调用InitializeSingleDevice初始化设备");
        }

        _server.Start();
        _isRunning = true;
        Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 模拟器启动成功，监听：{_server.LocalEndpoint}");
        Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 模拟设备：{_singleDevice.Name}（UnitId=1，固定）");

        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                using var connectCts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken);
                connectCts.CancelAfter(5000);
                var client = await _server.AcceptTcpClientAsync(connectCts.Token);
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] TCP服务连接成功：{client.Client.RemoteEndPoint}");
                _ = HandleTcpClientRequestAsync(client, stoppingToken);
            }
            catch (OperationCanceledException) { }
            catch (Exception ex)
            {
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 模拟器监听异常：{ex.Message}，1秒后重试");
                await Task.Delay(1000, stoppingToken);
            }
        }
    }

    public void Stop()
    {
        if (_isRunning)
        {
            _server.Stop();
            _isRunning = false;
            Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 模拟器已停止");
        }
    }

    // 【修改】仅处理UnitId=1的请求，无需多设备判断
    private async Task HandleTcpClientRequestAsync(TcpClient client, CancellationToken stoppingToken)
    {
        try
        {
            using var stream = client.GetStream();
            var buffer = new byte[1024];
            var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, stoppingToken);

            if (bytesRead < 8)
            {
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 无效请求：长度不足（{bytesRead}字节 < 8字节）");
                return;
            }

            // 解析Modbus头部（不变）
            ushort transactionId = ConvertBigEndianToUInt16(buffer, 0);
            ushort protocolId = ConvertBigEndianToUInt16(buffer, 2);
            byte requestUnitId = buffer[6];
            byte functionCode = buffer[7];

            if (protocolId != 0)
            {
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 无效协议ID：{protocolId}（必须为0）");
                var errorResp = BuildErrorResponse(transactionId, requestUnitId, functionCode, 0x01);
                await stream.WriteAsync(errorResp, 0, errorResp.Length, stoppingToken);
                return;
            }

            // 【修改】仅支持UnitId=1，其他直接拒绝
            if (requestUnitId != FixedUnitId)
            {
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 不支持的UnitId：{requestUnitId}（仅支持1）");
                var errorResp = BuildErrorResponse(transactionId, requestUnitId, functionCode, 0x01);
                await stream.WriteAsync(errorResp, 0, errorResp.Length, stoppingToken);
                return;
            }

            // 仅支持功能码0x03（读寄存器）
            if (functionCode != 0x03)
            {
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 不支持的功能码：0x{functionCode:X2}（仅支持0x03）");
                var errorResp = BuildErrorResponse(transactionId, requestUnitId, functionCode, 0x01);
                await stream.WriteAsync(errorResp, 0, errorResp.Length, stoppingToken);
                return;
            }

            // 解析寄存器请求（不变）
            if (bytesRead < 12)
            {
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 读寄存器请求格式错误：长度不足12字节");
                return;
            }
            ushort startAddr = ConvertBigEndianToUInt16(buffer, 8);
            ushort regCount = ConvertBigEndianToUInt16(buffer, 10);

            Console.WriteLine(
                $"[{DateTime.Now:HH:mm:ss}] 收到采集请求：事务ID={transactionId}，起始地址=0x{startAddr:X4}，数量={regCount}");

            // 读取寄存器（不变）
            var (isValid, regValues, errorCode) = _singleDevice!.GetRegisters(startAddr, regCount);
            if (!isValid)
            {
                Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 寄存器请求无效：错误码0x{errorCode:X2}");
                var errorResp = BuildErrorResponse(transactionId, requestUnitId, functionCode, errorCode);
                await stream.WriteAsync(errorResp, 0, errorResp.Length, stoppingToken);
                return;
            }

            // 构造响应（不变）
            var successResp = BuildSuccessResponse(transactionId, FixedUnitId, functionCode, regValues);
            await stream.WriteAsync(successResp, 0, successResp.Length, stoppingToken);
            Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 响应成功：事务ID={transactionId}，返回{regValues.Length}个寄存器值");

        }
        catch (Exception ex)
        {
            Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] 处理请求异常：{ex.Message}");
        }
        finally
        {
            if (client.Connected) client.Close();
        }
    }

    #region 协议辅助方法（不变）
    private ushort ConvertBigEndianToUInt16(byte[] buffer, int offset)
    {
        return (ushort)((buffer[offset] << 8) | buffer[offset + 1]);
    }

    private byte[] ConvertUInt16ToBigEndian(ushort value)
    {
        return new byte[] { (byte)(value >> 8), (byte)(value & 0xFF) };
    }

    private byte[] BuildSuccessResponse(ushort transactionId, byte unitId, byte functionCode, ushort[] regValues)
    {
        int dataLength = regValues.Length * 2;
        byte[] mbap = new byte[7];
        Array.Copy(ConvertUInt16ToBigEndian(transactionId), 0, mbap, 0, 2);
        Array.Copy(ConvertUInt16ToBigEndian((ushort)0), 0, mbap, 2, 2);
        ushort pduLength = (ushort)(3 + dataLength);
        Array.Copy(ConvertUInt16ToBigEndian(pduLength), 0, mbap, 4, 2);
        mbap[6] = unitId;

        byte[] pdu = new byte[2 + dataLength];
        pdu[0] = functionCode;
        pdu[1] = (byte)dataLength;
        for (int i = 0; i < regValues.Length; i++)
        {
            Array.Copy(ConvertUInt16ToBigEndian(regValues[i]), 0, pdu, 2 + i * 2, 2);
        }

        byte[] fullResp = new byte[mbap.Length + pdu.Length];
        Array.Copy(mbap, 0, fullResp, 0, mbap.Length);
        Array.Copy(pdu, 0, fullResp, mbap.Length, pdu.Length);
        return fullResp;
    }

    private byte[] BuildErrorResponse(ushort transactionId, byte unitId, byte functionCode, byte errorCode)
    {
        byte[] mbap = new byte[7];
        Array.Copy(ConvertUInt16ToBigEndian(transactionId), 0, mbap, 0, 2);
        Array.Copy(ConvertUInt16ToBigEndian((ushort)0), 0, mbap, 2, 2);
        Array.Copy(ConvertUInt16ToBigEndian((ushort)3), 0, mbap, 4, 2);
        mbap[6] = unitId;

        byte[] pdu = new byte[2];
        pdu[0] = (byte)(functionCode | 0x80);
        pdu[1] = errorCode;

        byte[] fullResp = new byte[mbap.Length + pdu.Length];
        Array.Copy(mbap, 0, fullResp, 0, mbap.Length);
        Array.Copy(pdu, 0, fullResp, mbap.Length, pdu.Length);
        return fullResp;
    }
    #endregion
}

/// <summary>
/// 设备模型（固定UnitId=1）
/// </summary>
internal class ModbusDevice
{
    public byte UnitId { get; } = 1; // 固定UnitId=1
    public string Name { get; }
    private readonly Dictionary<ushort, ushort> _registers;

    public ModbusDevice(byte unitId, string name, Dictionary<ushort, ushort> registers)
    {
        // 强制UnitId=1，忽略传入值
        if (unitId != 1)
        {
            throw new InvalidOperationException("模拟器仅支持UnitId=1");
        }
        Name = name;
        _registers = new Dictionary<ushort, ushort>(registers);
    }

    public (bool IsValid, ushort[] Values, byte ErrorCode) GetRegisters(ushort startAddr, ushort count)
    {
        if (count < 1 || count > 125)
            return (false, null, 0x03);

        var values = new ushort[count];
        for (int i = 0; i < count; i++)
        {
            ushort address = (ushort)(startAddr + i);
            if (!_registers.TryGetValue(address, out var value))
                return (false, null, 0x02);
            values[i] = value;
        }
        return (true, values, 0);
    }

    public void UpdateRegisterValue(ushort addr, ushort newValue)
    {
        if (_registers.ContainsKey(addr))
            _registers[addr] = newValue;
        else
            throw new KeyNotFoundException($"寄存器地址0x{addr:X4}不存在");
    }
}